<template>
  <el-container>
    <el-header style="height: auto">
      <el-form :model="queryInfo" ref="queryForm" size="small" :inline="true">
        <el-form-item prop="roleName">
          <el-input v-model="queryInfo.roleName" @keyup.enter.native="$event.target.blur"
                    placeholder="搜索角色名"
                    prefix-icon="el-icon-search"></el-input>
        </el-form-item>
        <el-form-item prop="status">
          <el-select clearable v-model="queryInfo.status" placeholder="请选择角色状态" style="margin-left: 5px">
            <el-option
              v-for="item in status"
              :key="item.type"
              :label="item.info"
              :value="item.type">
            </el-option>
          </el-select>
        </el-form-item>
        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
        <el-button type="primary" style="margin-left: 5px" icon="el-icon-search" @click="getRoleInfo"
                   v-hasPermi="['system:role:query']">查询
        </el-button>
        <el-button type="primary" style="margin-left: 5px" icon="el-icon-plus" @click="showAddDialog"
                   v-hasPermi="['system:role:add']">添加
        </el-button>
      </el-form>
    </el-header>

    <el-main>
      <!--操作的下拉框-->
      <el-select @change="selectChange" clearable v-if="selectedInTable.length !== 0" v-model="selected"
                 :placeholder="'已选择' + selectedInTable.length + '项'" style="margin-bottom: 25px;">

        <el-option value="on" v-hasPermi="['system:role:statusOn']">
          <span style="float: left">启用</span>
          <span style="float: right; color: #8492a6; font-size: 13px">on</span>
        </el-option>
        <el-option value="off" v-hasPermi="['system:role:statusOff']">
          <span style="float: left">禁用</span>
          <span style="float: right; color: #8492a6; font-size: 13px">off</span>
        </el-option>
        <el-option value="delete" v-hasPermi="['system:role:remove']">
          <span style="float: left">删除</span>
          <span style="float: right; color: #8492a6; font-size: 13px">delete</span>
        </el-option>

      </el-select>

      <el-table
        v-hasPermi="['system:role:query']"
        ref="roleTable"
        highlight-current-row
        :row-key="roleRowKeys"
        v-loading="loading"
        :data="roleInfo"
        tooltip-effect="dark"
        style="width: 100%"
        height="91%"
        @selection-change="handleSelectionChange"
        :default-sort="{prop: 'roleName', order: 'ascending'}">

        <el-table-column align="center"
                         type="selection"
                         :reserve-selection="true"
                         width="55">
        </el-table-column>

        <el-table-column align="center"
                         prop="roleName"
                         sortable
                         label="角色名">
          <template slot-scope="scope">
            <el-popover trigger="hover" placement="top">
              <p>{{ scope.row.remark }}</p>
              <div slot="reference" class="name-wrapper">
                <el-tag size="medium">{{ scope.row.roleName }}</el-tag>
              </div>
            </el-popover>
          </template>
        </el-table-column>

        <el-table-column align="center"
                         prop="roleKey"
                         sortable
                         label="角色编码">
        </el-table-column>

        <el-table-column align="center"
                         label="生效时间">
          <template slot-scope="scope">
            {{ scope.row.startTime }}
          </template>
        </el-table-column>

        <el-table-column align="center"
                         label="失效时间">
          <template slot-scope="scope">
            {{ scope.row.endTime }}
          </template>
        </el-table-column>

        <el-table-column align="center"
                         label="创建时间">
          <template slot-scope="scope">
            {{ scope.row.createTime }}
          </template>
        </el-table-column>

        <el-table-column align="center"
                         label="修改时间">
          <template slot-scope="scope">
            {{ scope.row.updateTime }}
          </template>
        </el-table-column>

        <el-table-column align="center"
                         label="状态">
          <template slot-scope="scope">
            <i v-if="scope.row.status == 0" class="el-icon-check"
               style="font-size: 20px; background: #E8F4FF; color: #1890FF"></i>
            <i v-else class="el-icon-close" style="font-size: 20px; background: #FFEDED; color: #FF4949"></i>
          </template>
        </el-table-column>

        <el-table-column
          fixed="right"
          align="center"
          label="操作">
          <template slot-scope="scope">
            <el-button @click="showDeleteRoleDialog(scope.row)" type="text" size="small"
                       v-hasPermi="['system:role:remove']">删除
            </el-button>
            <el-button @click="showUpdateDialog(scope.row)" type="text" size="small" v-hasPermi="['system:role:edit']">
              修改
            </el-button>
            <el-button @click="showSetDialog(scope.row)" type="text" size="small" v-hasPermi="['system:role:permiSet']">
              权限设置
            </el-button>
          </template>
        </el-table-column>

      </el-table>

      <!--分页-->
      <el-pagination style="margin-top: 25px"
                     @size-change="handleSizeChange"
                     @current-change="handleCurrentChange"
                     :current-page="queryInfo.pageNo"
                     :page-sizes="[10, 20, 30, 50]"
                     :page-size="queryInfo.pageSize"
                     layout="total, sizes, prev, pager, next, jumper"
                     :total="roleTotal">
      </el-pagination>

    </el-main>

    <el-dialog title="添加角色" :visible.sync="addTableVisible" width="30%" @close="resetAddForm"
               :close-on-click-modal="false"
               center>

      <el-form :model="addForm" :rules="addFormRules" ref="addForm">

        <el-form-item label="角色名" prop="roleName">
          <el-input v-model="addForm.roleName"></el-input>
        </el-form-item>

        <el-form-item label="角色编码" prop="roleKey">
          <el-input v-model="addForm.roleKey"></el-input>
        </el-form-item>

        <el-form-item label="生效时间" prop="startTime">
          <el-date-picker style="margin-left: 5px"
                          v-model="addForm.startTime"
                          value-format="yyyy-MM-dd HH:mm:ss"
                          type="datetime" placeholder="生效时间">
          </el-date-picker>
        </el-form-item>

        <el-form-item label="失效时间" prop="endTime">
          <el-date-picker style="margin-left: 5px"
                          v-model="addForm.endTime"
                          value-format="yyyy-MM-dd HH:mm:ss"
                          type="datetime" placeholder="失效时间">
          </el-date-picker>
        </el-form-item>

        <el-form-item label="备注" prop="remark">
          <el-input v-model="addForm.remark"></el-input>
        </el-form-item>

        <el-form-item label="角色状态" prop="status">
          <el-select v-model="addForm.status" placeholder="请选择角色状态">
            <el-option label="有效" value="0"></el-option>
            <el-option label="无效" value="1"></el-option>
          </el-select>
        </el-form-item>
      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button @click="addTableVisible = false">取 消</el-button>
        <el-button type="primary" @click="addRole">确 定</el-button>
      </div>
    </el-dialog>

    <el-dialog title="修改角色" :visible.sync="updateVisible" width="30%" :close-on-click-modal="false"
               @close="resetUpdateForm"
               center>

      <el-form :model="updateForm" :rules="addFormRules" ref="updateForm">

        <el-form-item label="角色名" prop="roleName">
          <el-input v-model="updateForm.roleName" disabled></el-input>
        </el-form-item>

        <el-form-item label="角色编码" prop="roleKey">
          <el-input v-model="updateForm.roleKey"></el-input>
        </el-form-item>

        <el-form-item label="生效时间" prop="startTime">
          <el-date-picker style="margin-left: 5px"
                          v-model="updateForm.startTime"
                          value-format="yyyy-MM-dd HH:mm:ss"
                          type="datetime" placeholder="生效时间">
          </el-date-picker>
        </el-form-item>

        <el-form-item label="失效时间" prop="endTime">
          <el-date-picker style="margin-left: 5px"
                          v-model="updateForm.endTime"
                          value-format="yyyy-MM-dd HH:mm:ss"
                          type="datetime" placeholder="失效时间">
          </el-date-picker>
        </el-form-item>

        <el-form-item label="备注" prop="remark">
          <el-input v-model="updateForm.remark"></el-input>
        </el-form-item>

        <el-form-item label="角色状态" prop="status">
          <el-select v-model="updateForm.status" placeholder="请选择角色状态">
            <el-option label="有效" value="0"></el-option>
            <el-option label="无效" value="1"></el-option>
          </el-select>
        </el-form-item>
      </el-form>

      <div slot="footer" class="dialog-footer">
        <el-button @click="updateVisible = false">取 消</el-button>
        <el-button type="primary" @click="updateRole">确 定</el-button>
      </div>
    </el-dialog>

    <!-- 权限设置对话框 -->
    <el-dialog title="权限设置" :visible.sync="setVisible" width="500px" append-to-body :close-on-click-modal="false">
      <el-form :model="setForm" label-width="80px">
        <el-form-item label="角色名称">
          <el-input v-model="setForm.roleName" :disabled="true"/>
        </el-form-item>
        <el-form-item label="角色编码">
          <el-input v-model="setForm.roleKey" :disabled="true"/>
        </el-form-item>
        <el-form-item label="菜单权限">
          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event)">展开</el-checkbox>
          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event)">全选</el-checkbox>
          <el-tree
            class="tree-border"
            :data="menuOptions"
            show-checkbox
            ref="menu"
            node-key="menuId"
            :check-strictly="false"
            empty-text="加载中，请稍候"
            :props="defaultProps"
            @check-change="handleMenuSectionChange"
          ></el-tree>
        </el-form-item>
      </el-form>
      <div slot="footer" class="dialog-footer">
        <el-button type="primary" @click="addMenuToRole">确定</el-button>
        <el-button @click="cancel">取 消</el-button>
      </div>
    </el-dialog>
  </el-container>
</template>

<script>
import {handleTree} from "@/plugins/handleTree";

export default {
  name: 'RoleManage',
  data() {
    //自定义角色名校验规则
    var validateRoleName = (rule, value, callback) => {
      this.$http.get(this.API.checkRoleName + '/' + this.addForm.roleName).then((resp) => {
        if (resp.data.code === 200) {
          callback()
        } else {
          callback(new Error('角色名已存在'))
        }
      })
    }
    return {
      //查询角色的参数
      queryInfo: {
        'roleName': '',
        'status': '',
        'pageNo': 1,
        'pageSize': 20
      },
      //角色状态查询下拉框信息
      status: [
        {
          info: '全部',
          type: ''
        },
        {
          info: '有效',
          type: 0
        },
        {
          info: '无效',
          type: 1
        }
      ],
      //被选择的表格中的行数据
      selectedInTable: [],
      //下拉框所选择的数据
      selected: '',
      //表格信息加载
      loading: true,
      //角色信息
      roleInfo: [],
      addTableVisible: false,
      //添加角色的表单信息
      addForm: {
        'roleName': '',
        'roleKey': '',
        'startTime': '',
        'endTime': '',
        'status': '0',
        'remark': ''
      },
      //修改角色的表单信息
      updateForm: {
        'roleName': '',
        'roleKey': '',
        'startTime': '',
        'endTime': '',
        'status': '0',
        'remark': ''
      },
      addFormRules: {
        roleName: [
          {
            validator: validateRoleName,
            trigger: 'blur'
          },
          {
            required: true,
            message: '请输入角色名称',
            trigger: 'blur'
          },
          {
            max: 100,
            message: '角色名称不能超过100个字符'
          }
        ],
        roleKey: [
          {
            required: true,
            trigger: 'blur',
            message: '角色编码必填'
          },{
            max: 50,
            message: '角色编码不能超过50个字符',
          }
        ],
        remark: [
          {
            max: 500,
            message: '格式错误，长度应小于500',
            trigger: 'blur'
          }
        ],
      },
      //修改用户信息的对话框是否显示
      updateVisible: false,
      roleTotal: 0,
      setVisible: false,
      setForm: {},
      menuExpand: false,
      menuNodeAll: false,
      // 菜单列表
      menuOptions: [],
      defaultProps: {
        children: "children",
        label: "menuName"
      },
      //分配菜单的角色ID
      addMenuRoleId: '',
    }
  },
  created() {
    this.getRoleInfo()
  },
  methods: {
    roleRowKeys(row) {
      return row.roleId
    },
    //获取角色信息
    getRoleInfo(isClear) {
      this.loading = true
      this.$http.get(this.API.getRoleInfo, {params: this.queryInfo}).then((resp) => {
        if (resp.data.code === 200) {
          if (isClear != false) {
            this.$refs.roleTable.clearSelection()  //清除复选框选择
          }
          this.roleInfo = resp.data.data.roles;
          this.roleTotal = resp.data.data.total;
          this.loading = false;
        } else {
          this.$notify({
            title: 'Tips',
            message: '获取信息失败',
            type: 'error',
            duration: 2000
          })
        }
      })
    },
    //重置搜索条件表单
    resetQuery() {
      this.$refs['queryForm'].resetFields()
      this.getRoleInfo()
    },
    //获取菜单列表
    getMenuInfoAndSel() {
      this.$http.get(this.API.getMenuByQuInfo).then((resp) => {
        if (resp.data.code === 200) {
          this.menuOptions = handleTree(resp.data.data.menus, "menuId");
          this.$nextTick(() => {
            this.$http.get(this.API.getMenuByRoleId, {params: {'roleId': this.addMenuRoleId}}).then((resp) => {
              if (resp.data.code === 200) {
                let menuData = resp.data.data
                menuData.forEach((v) => {
                  this.$nextTick(() => {
                    this.$refs.menu.setChecked(v, true, false);
                  })
                })
              } else {
                this.$notify({
                  title: 'Tips',
                  message: '获取角色失败',
                  type: 'error',
                  duration: 2000
                })
              }
            })
          })
        } else {
          this.$notify({
            title: 'Tips',
            message: '获取信息失败',
            type: 'error',
            duration: 2000
          })
        }
      })
    },
    //表格某一行被选中
    handleSelectionChange(val) {
      this.selectedInTable = val
    },
    //分页插件的大小改变
    handleSizeChange(val) {
      this.queryInfo.pageSize = val
      this.getRoleInfo(false)
    },
    //分页插件的页数
    handleCurrentChange(val) {
      this.queryInfo.pageNo = val
      this.getRoleInfo(false)
    },
    //点击添加按钮
    showAddDialog() {
      this.addTableVisible = true
    },
    //表单信息重置
    resetAddForm() {
      //清空表格数据
      this.$refs['addForm'].resetFields()
    },
    resetUpdateForm() {
      if (this.$refs['updateForm']) {
        this.$nextTick(() => {
          this.$refs['updateForm'].resetFields()
        })
      }
    },
    //添加角色
    addRole() {
      this.$refs['addForm'].validate((valid) => {
        if (valid) {
          this.$http.post(this.API.addRole, this.addForm).then((resp) => {
            if (resp.data.code === 200) {
              this.getRoleInfo()
              this.$notify({
                title: 'Tips',
                message: resp.data.message,
                type: 'success',
                duration: 2000
              })
            } else {
              this.$notify({
                title: 'Tips',
                message: resp.data.message,
                type: 'error',
                duration: 2000
              })
            }
            this.addTableVisible = false
          })
        } else {
          this.$message.error('请检查您所填写的信息是否有误')
          return false
        }
      })
    },
    //功能下拉框被选择
    selectChange(val) {
      let tipInfo = ''
      if (val === 'on') {
        tipInfo = '是否继续启用所选角色?'
      } else if (val === 'off') {
        tipInfo = '是否继续禁用所选角色?'
      } else if (val === 'delete') {
        tipInfo = '此操作将永久删除所选角色, 是否继续?'
      }
      this.$confirm(tipInfo, '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        //清空上一次的操作
        this.selected = ''
        //表格中所选中的角色的id
        let roleIds = []
        this.selectedInTable.map(item => {
          roleIds.push(item.roleId)
        })
        if (val === 'on') {//状态设置为有效
          this.$http.get(this.API.handleRole + '/' + 1, {params: {'roleIds': roleIds.join(',')}}).then((resp) => {
            if (resp.data.code === 200) {
              //删除成功后,回调更新角色数据
              this.getRoleInfo()
              this.$notify({
                title: 'Tips',
                message: '操作成功',
                type: 'success',
                duration: 2000
              })
            } else {
              this.$notify({
                title: 'Tips',
                message: '操作失败',
                type: 'error',
                duration: 2000
              })
            }
          })
        } else if (val === 'off') {//状态设置为无效
          this.$http.get(this.API.handleRole + '/' + 2, {params: {'roleIds': roleIds.join(',')}}).then((resp) => {
            if (resp.data.code === 200) {
              //删除成功后,回调更新角色数据
              this.getRoleInfo()
              this.$notify({
                title: 'Tips',
                message: '操作成功',
                type: 'success',
                duration: 2000
              })
            } else {
              this.$notify({
                title: 'Tips',
                message: '操作失败',
                type: 'error',
                duration: 2000
              })
            }
          })
        } else if (val === 'delete') {//删除角色
          this.$http.get(this.API.handleRole + '/' + 3, {params: {'roleIds': roleIds.join(',')}}).then((resp) => {
            if (resp.data.code === 200) {
              //删除成功后,回调更新角色数据
              this.getRoleInfo()
              this.$notify({
                title: 'Tips',
                message: '操作成功',
                type: 'success',
                duration: 2000
              })
            } else {
              this.$notify({
                title: 'Tips',
                message: '操作失败',
                type: 'error',
                duration: 2000
              })
            }
          })
        }
        this.getRoleInfo()
        this.$message({
          type: 'success',
          message: '操作成功!'
        });
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消操作'
        });
      });
    },
    //点击修改按钮
    showUpdateDialog(row) {
      this.$nextTick(() => {
        this.updateForm = Object.assign({}, row)
        this.updateForm.password = ''
      })
      this.updateVisible = true
    },
    //修改角色
    updateRole() {
      this.$refs['updateForm'].validate((valid) => {
        if (valid) {
          this.$confirm("是否确认修改角色？", '提示', {
            confirmButtonText: '确定',
            cancelButtonText: '取消',
            type: 'warning'
          }).then(() => {
            this.$http.post(this.API.updateRole, this.updateForm).then((resp) => {
              if (resp.data.code === 200) {
                this.getRoleInfo()
                this.$notify({
                  title: 'Tips',
                  message: resp.data.message,
                  type: 'success',
                  duration: 2000
                })
              } else {
                this.$notify({
                  title: 'Tips',
                  message: resp.data.message,
                  type: 'error',
                  duration: 2000
                })
              }
              this.updateVisible = false
            })
          }).catch(() => {
            this.$message({
              type: 'info',
              message: '已取消操作'
            });
          });
        } else {
          this.$message.error('请检查您所填写的信息是否有误')
          return false
        }
      })
    },
    showSetDialog(row) {
      this.getMenuInfoAndSel()
      this.addMenuRoleId = row.roleId
      this.setForm.roleName = row.roleName
      this.setForm.roleKey = row.roleKey
      this.setVisible = true
    },
    // 树权限（展开/折叠）
    handleCheckedTreeExpand(value) {
      let treeList = this.menuOptions;
      for (let i = 0; i < treeList.length; i++) {
        this.$refs.menu.store.nodesMap[treeList[i].menuId].expanded = value;
      }
    },
    // 树权限（全选/全不选）
    handleCheckedTreeNodeAll(value) {
      this.$refs.menu.setCheckedNodes(value ? this.menuOptions : []);
    },
    // 取消按钮
    cancel() {
      this.setVisible = false;
    },
    //分配角色
    addMenuToRole() {
      this.$confirm("是否确认分配权限？", '提示', {
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        type: 'warning'
      }).then(() => {
        //表格中所选中的角色的id
        let menuIds = this.getMenuAllCheckedKeys();
        this.$http.get(this.API.addMenuToRole + '/' + this.addMenuRoleId, {params: {'menuIds': menuIds.join(',')}}).then((resp) => {
          if (resp.data.code === 200) {
            this.setVisible = false
            this.$notify({
              title: 'Tips',
              message: '操作成功',
              type: 'success',
              duration: 2000
            })
          } else {
            this.$notify({
              title: 'Tips',
              message: resp.data.message,
              type: 'error',
              duration: 2000
            })
          }
        })
      }).catch(() => {
        this.$message({
          type: 'info',
          message: '已取消操作'
        });
      });
    },
    //处理菜单权限被选中
    handleMenuSectionChange(val) {
      this.selectedMenuTable = val
    },
    // 所有菜单节点数据
    getMenuAllCheckedKeys() {
      // 目前被选中的菜单节点
      let checkedKeys = this.$refs.menu.getCheckedKeys();
      // 半选中的菜单节点
      let halfCheckedKeys = this.$refs.menu.getHalfCheckedKeys();
      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
      return checkedKeys;
    },
    //显示删除角色确认框
    showDeleteRoleDialog(row) {
      const h = this.$createElement;
      this.$msgbox({
        title: '消息',
        message: h('p', null, [
          h('span', null, '是否确认删除角色： '),
          h('i', {style: 'color: teal'}, row.roleName)
        ]),
        showCancelButton: true,
        confirmButtonText: '确定',
        cancelButtonText: '取消',
        beforeClose: (action, instance, done) => {
          instance.confirmButtonLoading = false
          if (action === 'confirm') {
            instance.confirmButtonLoading = true;
            instance.confirmButtonText = '执行中...';
            this.$http.get(this.API.handleRole + '/' + 3, {params: {'roleIds': row.roleId}}).then((resp) => {
              if (resp.data.code === 200) {
                //删除成功后,回调更新数据
                this.getRoleInfo()
                instance.confirmButtonLoading = false
                done()
                this.$notify({
                  title: 'Tips',
                  message: resp.data.message,
                  type: 'success',
                  duration: 2000
                })
              } else {
                this.$notify({
                  title: 'Tips',
                  message: '操作失败',
                  type: 'error',
                  duration: 2000
                })
              }
            })
          } else {
            done();
          }
        }
      }).catch(() => {
      })
    },
  },
  computed: {}
}
</script>

<style scoped lang="scss">
.el-container {
  width: 100%;
  height: 100%;
}

.el-input {
  width: 150px;
}

.el-container {
  animation: leftMoveIn .7s ease-in;
}

@keyframes leftMoveIn {
  0% {
    transform: translateX(-100%);
    opacity: 0;
  }
  100% {
    transform: translateX(0%);
    opacity: 1;
  }
}

.role {
  color: #606266;
}

/deep/ .el-table thead {
  color: rgb(85, 85, 85) !important;
}

/*表格的头部样式*/
/deep/ .has-gutter tr th {
  background: rgb(242, 243, 244);
  color: rgb(85, 85, 85);
  font-weight: bold;
}

.el-table {
  box-shadow: 0 0 1px 1px gainsboro;
}
</style>
